Conversation
Viewers vote via chat keywords (!forward, !left, etc.). Winning command each window is published as Twist on cmd_vel. Four voting modes: - plurality: most votes wins (classic Twitch Plays) - majority: winner needs >50% - weighted_recent: later votes count more - runoff: instant runoff if no majority - dimos/stream/twitch/module.py — TwitchChat module + vote tallying - Blueprint: unitree-go2-twitch (Go2 + TwitchChat) - examples/twitch_plays/ — README + standalone runner
- Add .*/native/build(/|$) to mypy exclude pattern to skip CMake _deps directories (dimos_lcm-src has invalid Python package name) - Fix type: ignore comments to cover import-not-found alongside import-untyped for twitchio and onnxruntime - Fix Counter[str] += float type error in weighted_recent tally
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ure, add tests - Extract _build_twitch_message and _on_message_received hook in TwitchChat so TwitchVotes doesn't duplicate badge parsing - Add threading.Event stop signal to _vote_loop for clean shutdown - Widen message_to_choice return type to Any (supports lambda short-circuit) - Add 27 unit tests for TwitchMessage, tally functions, and filter patterns Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- inject_message now calls _on_message_received hook (votes work in local mode) - find_one uses word-boundary matching (prevents "backwards" matching "back") - stop() wraps bot close in try/except so cleanup always runs - Remove config mutation in TwitchVotes.start() (patterns don't affect voting) - _tally_weighted_recent uses float weights instead of int truncation - _vote_loop preserves votes arriving after window ends instead of clearing all - Deduplicate votes per voter per window (prevents spam) - Compile patterns before local-only early return Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR introduces Twitch chat integration for DimOS, adding two new modules ( Key findings:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant TC as TwitchIRC
participant Bot as _TwitchBot
participant Chat as TwitchChat
participant Votes as TwitchVotes
participant VL as VoteLoop
participant Bridge as ChoiceToCmdVel
participant Robot as Go2 cmd_vel
TC->>Bot: IRC message
Bot->>Chat: on_message_cb(message)
Chat->>Chat: _build_twitch_message()
Chat->>Chat: raw_messages.publish(msg)
Chat->>Chat: _publish_if_matched(msg)
Chat->>Votes: _on_message_received(msg)
Votes->>Votes: message_to_choice(msg, choices)
Votes->>Votes: append to _votes deque
Note over VL: every vote_window_seconds
VL->>Votes: acquire _votes_lock
VL->>VL: _tally(votes, mode)
VL->>Bridge: chat_vote_choice.publish(TwitchChoice)
Bridge->>Robot: cmd_vel.publish(Twist) x10
Bridge->>Robot: cmd_vel.publish(Twist zero)
|
Draft b/c: probably going to change some file names, might change filtering for the basic module. Need to check the voter de-dup logic (what's the refresh rate)
Problem
To transcend to a higher state of society, dangerous robots need to be controllable by Twitch chat -- the ultimate democratic source of group-intelligence.
Solution
Two new modules:
TwitchChat Module
TwitchMessageonraw_messagesfiltered_messagesstream, with module config for:filter_is_mod,filter_is_subscriber,filter_author,filter_contentinject_message()for testing.TwitchVotes
TwitchChoiceobjects)New Blueprint
unitree-go2-twitchexamples/twitch_plays/run.pyshows the full pipelineDesign decisions:
Breaking Changes
None
How to Test
Unit tests below, but a full/real test can be run by setting up keys/dimos and then doing
python examples/twitch_plays/run.py(see examples/twitch_plays/readme.md for details)Contributor License Agreement